import Cookies from 'js-cookie'
import config from '@/config'
import { forEach, hasOneOf, objEqual } from '@/utils/tools'
const { title, cookieExpires, useI18n } = config

export const TOKEN_KEY: string = 'token'

export const setToken = (token: string): void => {
  Cookies.set(TOKEN_KEY, token, { expires: cookieExpires || 1 })
}

export const getToken = (): string | boolean => {
  const token = Cookies.get(TOKEN_KEY)
  if (token) return token
  else return false
}

export const hasChild = (item: any): boolean => {
  return item.children && item.children.length !== 0
}

const showThisMenuEle = (item: any, access: string[]): boolean => {
  if (item.meta && item.meta.access && item.meta.access.length) {
    if (hasOneOf(item.meta.access, access)) return true
    else return false
  } else return true
}

export const getMenuByRouter = (list: any[], access: string[]): any[] => {
  const res: any[] = []
  forEach(list, (item) => {
    if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
      const obj = {
        icon: (item.meta && item.meta.icon) || '',
        name: item.name,
        meta: item.meta
      }
      if (
        (hasChild(item) || (item.meta && item.meta.showAlways)) &&
        showThisMenuEle(item, access)
      ) {
        obj.children = getMenuByRouter(item.children, access)
      }
      if (item.meta && item.meta.href) obj.href = item.meta.href
      if (showThisMenuEle(item, access)) res.push(obj)
    }
  })
  return res
}

export const getBreadCrumbList = (route: any, homeRoute: any): any[] => {
  const homeItem = { ...homeRoute, icon: homeRoute.meta.icon }
  const routeMetched = route.matched
  if (routeMetched.some((item) => item.name === homeRoute.name)) return [homeItem]
  const res = routeMetched
    .filter((item) => {
      return item.meta === undefined || !item.meta.hideInBread
    })
    .map((item) => {
      const meta = { ...item.meta }
      if (meta.title && typeof meta.title === 'function') {
        meta.__titleIsFunction__ = true
        meta.title = meta.title(route)
      }
      const obj = {
        icon: (item.meta && item.meta.icon) || '',
        name: item.name,
        meta: meta
      }
      return obj
    })
  res = res.filter((item) => {
    return !item.meta.hideInMenu
  })
  return [{ ...homeItem, to: homeRoute.path }, ...res]
}

export const getRouteTitleHandled = (route: any): any => {
  const router = { ...route }
  const meta = { ...route.meta }
  const title = ''
  if (meta.title) {
    if (typeof meta.title === 'function') {
      meta.__titleIsFunction__ = true
      title = meta.title(router)
    } else title = meta.title
  }
  meta.title = title
  router.meta = meta
  return router
}

export const showTitle = (item: any, vm: any): string => {
  const { title, __titleIsFunction__ } = item.meta
  if (!title) return ''
  if (useI18n) {
    if (title.includes('{{') && title.includes('}}') && useI18n)
      title = title.replace(/({{[\s\S]+?}})/, (m: string, str: string) =>
        str.replace(/{{([\s\S]*)}}/, (m: string, _: string) => vm.$t(_.trim()))
      )
    else if (__titleIsFunction__) title = item.meta.title
    else title = vm.$t(item.name)
  } else title = (item.meta && item.meta.title) || item.name
  return title
}

export const setTagNavListInLocalstorage = (list: any[]): void => {
  localStorage.tagNaveList = JSON.stringify(list)
}

export const getTagNavListFromLocalstorage = (): any[] => {
  const list = localStorage.tagNaveList
  return list ? JSON.parse(list) : []
}

export const getHomeRoute = (routers: any[], homeName: string = 'home'): any => {
  const i = -1
  const len = routers.length
  const homeRoute = {}
  while (++i < len) {
    const item = routers[i]
    if (item.children && item.children.length) {
      const res = getHomeRoute(item.children, homeName)
      if (res.name) return res
    } else {
      if (item.name === homeName) homeRoute = item
    }
  }
  return homeRoute
}

export const getNewTagList = (list: any[], newRoute: any): any[] => {
  const { name, path, meta } = newRoute
  const newList = [...list]
  if (newList.findIndex((item) => item.name === name) >= 0) return newList
  else newList.push({ name, path, meta })
  return newList
}

const hasAccess = (access: string[], route: any): boolean => {
  if (route.meta && route.meta.access) return hasOneOf(access, route.meta.access)
  else return true
}

export const canTurnTo = (name: string, access: string[], routes: any[]): boolean => {
  const routePermissionJudge = (list: any[]): boolean => {
    return list.some((item) => {
      if (item.children && item.children.length) {
        return routePermissionJudge(item.children)
      } else if (item.name === name) {
        return hasAccess(access, item)
      }
    })
  }

  return routePermissionJudge(routes)
}

export const getParams = (url: string): { [key: string]: string } => {
  const keyValueArr = url.split('?')[1].split('&')
  const paramObj: { [key: string]: string } = {}
  keyValueArr.forEach((item) => {
    const keyValue = item.split('=')
    paramObj[keyValue[0]] = keyValue[1]
  })
  return paramObj
}

export const getNextRoute = (list: any[], route: any): any => {
  const res = {}
  if (list.length === 2) {
    res = getHomeRoute(list)
  } else {
    const index = list.findIndex((item) => routeEqual(item, route))
    if (index === list.length - 1) res = list[list.length - 2]
    else res = list[index + 1]
  }
  return res
}

export const doCustomTimes = (times: number, callback: (index: number) => void): void => {
  const i = -1
  while (++i < times) {
    callback(i)
  }
}

export const getArrayFromFile = (file: File): Promise<any[][]> => {
  const nameSplit = file.name.split('.')
  const format = nameSplit[nameSplit.length - 1]
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.readAsText(file) // 以文本格式读取
    const arr: any[][] = []
    reader.onload = function (evt: ProgressEvent<FileReader>) {
      const data = evt.target.result as string // 读到的数据
      const pasteData = data.trim()
      arr = pasteData
        .split(/[\n\u0085\u2028\u2029]|\r\n?/g)
        .map((row) => {
          return row.split('\t')
        })
        .map((item) => {
          return item[0].split(',')
        })
      if (format === 'csv') resolve(arr)
      else reject(new Error('[Format Error]:你上传的不是Csv文件'))
    }
  })
}

export const getTableDataFromArray = (array: any[][]): { columns: any[]; tableData: any[] } => {
  const columns: any[] = []
  const tableData: any[] = []
  if (array.length > 1) {
    const titles = array.shift()
    columns = titles.map((item) => {
      return {
        title: item,
        key: item
      }
    })
    tableData = array.map((item) => {
      const res: { [key: string]: string } = {}
      item.forEach((col, i) => {
        res[titles[i]] = col
      })
      return res
    })
  }
  return {
    columns,
    tableData
  }
}

export const findNodeUpper = (ele: HTMLElement, tag: string): HTMLElement | null => {
  if (ele.parentNode) {
    if (ele.parentNode.tagName === tag.toUpperCase()) {
      return ele.parentNode as HTMLElement
    } else {
      return findNodeUpper(ele.parentNode as HTMLElement, tag)
    }
  }
  return null
}

export const findNodeUpperByClasses = (ele: HTMLElement, classes: string[]): HTMLElement | null => {
  const parentNode = ele.parentNode as HTMLElement
  if (parentNode) {
    const classList = parentNode.classList
    if (classList && classes.every((className) => classList.contains(className))) {
      return parentNode
    } else {
      return findNodeUpperByClasses(parentNode, classes)
    }
  }
  return null
}

export const findNodeDownward = (ele: HTMLElement, tag: string): HTMLElement | null => {
  const tagName = tag.toUpperCase()
  if (ele.childNodes.length) {
    const i = -1
    const len = ele.childNodes.length
    while (++i < len) {
      const child = ele.childNodes[i] as HTMLElement
      if (child.tagName === tagName) return child
      else return findNodeDownward(child, tag)
    }
  }
  return null
}

export const showByAccess = (access: string[], canViewAccess: string[]): boolean => {
  return hasOneOf(canViewAccess, access)
}

export const routeEqual = (route1: any, route2: any): boolean => {
  const params1 = route1.params || {}
  const params2 = route2.params || {}
  const query1 = route1.query || {}
  const query2 = route2.query || {}
  return route1.name === route2.name && objEqual(params1, params2) && objEqual(query1, query2)
}

export const routeHasExist = (tagNavList: any[], routeItem: any): boolean => {
  const len = tagNavList.length
  const res = false
  doCustomTimes(len, (index) => {
    if (routeEqual(tagNavList[index], routeItem)) res = true
  })
  return res
}

export const localSave = (key: string, value: string): void => {
  localStorage.setItem(key, value)
}

export const localRead = (key: string): string => {
  return localStorage.getItem(key) || ''
}

export const scrollTop = (
  el: any,
  from: number = 0,
  to: number,
  duration: number = 500,
  endCallback?: () => void
): void => {
  if (!window.requestAnimationFrame) {
    window.requestAnimationFrame =
      window.webkitRequestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.msRequestAnimationFrame ||
      function (callback) {
        return window.setTimeout(callback, 1000 / 60)
      }
  }
  const difference = Math.abs(from - to)
  const step = Math.ceil((difference / duration) * 50)

  const scroll = (start: number, end: number, step: number) => {
    if (start === end) {
      endCallback && endCallback()
      return
    }

    const d = start + step > end ? end : start + step
    if (start > end) {
      d = start - step < end ? end : start - step
    }

    if (el === window) {
      window.scrollTo(d, d)
    } else {
      el.scrollTop = d
    }
    window.requestAnimationFrame(() => scroll(d, end, step))
  }
  scroll(from, to, step)
}

export const setTitle = (routeItem: any, vm: any): void => {
  const handledRoute = getRouteTitleHandled(routeItem)
  const pageTitle = showTitle(handledRoute, vm)
  const resTitle = pageTitle ? `${title} - ${pageTitle}` : title
  window.document.title = resTitle
}

export const GetRequest = (): { [key: string]: string } => {
  const url = location.search
  const theRequest: { [key: string]: string } = {}
  if (url.indexOf('?') != -1) {
    const str = url.substr(1)
    const strs = str.split('&')
    for (const i = 0; i < strs.length; i++) {
      theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1])
    }
  }
  return theRequest
}

export const writeLog = (key: string, message: string): void => {
  console.log(`[${key}]:${message}`)
}
